/*
 *  Copyright 2016 http://www.kedacomframework.org
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package com.kedacom.ctsp.authz.oauth2.controller;

import com.alibaba.fastjson.JSON;
import com.kedacom.ctsp.authz.entity.Authentication;
import com.kedacom.ctsp.authz.exception.UnauthorizedException;
import com.kedacom.ctsp.authz.oauth2.core.*;
import com.kedacom.ctsp.authz.oauth2.core.vo.AccessToken;
import com.kedacom.ctsp.authz.oauth2.core.vo.ClientQueryParam;
import com.kedacom.ctsp.authz.oauth2.entity.Client;
import com.kedacom.ctsp.authz.oauth2.entity.SimpleAccessToken;
import com.kedacom.ctsp.authz.oauth2.service.AccessTokenService;
import com.kedacom.ctsp.authz.oauth2.service.ClientService;
import com.kedacom.ctsp.authz.oauth2.service.OAuth2GrantService;
import com.kedacom.ctsp.authz.oauth2.service.client.HttpClientCredentialRequest;
import com.kedacom.ctsp.authz.oauth2.service.code.HttpAuthorizationCodeTokenRequest;
import com.kedacom.ctsp.authz.oauth2.service.password.HttpPasswordRequest;
import com.kedacom.ctsp.authz.oauth2.service.refresh.HttpRefreshTokenRequest;
import com.kedacom.ctsp.web.controller.message.ResponseMessage;
import io.swagger.annotations.Api;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/**
 * @author zhouhao
 */
@RestController
@Api(tags = "kedacom-oauth2", description = "OAuth2授权token获取", hidden = true)
@RequestMapping("${commons.web.mappings.oauth2_access_token:access_token}")
@Log4j
public class OAuth2AccessTokenController {

    @Resource
    private OAuth2GrantService oAuth2GrantService;
    @Autowired
    private ClientService clientService;
    @Autowired
    private AccessTokenService accessTokenService;
    @Autowired
    private LogoutHandler logoutHandler;

    /**
     * 根据code获取accessToken
     *
     * @param grantType
     * @param request
     * @return
     */
    @PostMapping
    public ResponseMessage<AccessToken> requestToken(@RequestParam("grant_type") String grantType, HttpServletRequest request) {
        com.kedacom.ctsp.authz.oauth2.entity.AccessToken accessToken = null;
        switch (grantType) {
            case GrantType.AUTHORIZATION_CODE:
                accessToken = oAuth2GrantService
                        .grant(GrantType.AUTHORIZATION_CODE, new HttpAuthorizationCodeTokenRequest(request));
                break;
            case GrantType.CLIENT_CREDENTIALS:
                accessToken = oAuth2GrantService
                        .grant(GrantType.CLIENT_CREDENTIALS, new HttpClientCredentialRequest(request));
                break;
            case GrantType.PASSWORD:
                accessToken = oAuth2GrantService
                        .grant(GrantType.PASSWORD, new HttpPasswordRequest(request));
                break;
            case GrantType.REFRESH_TOKEN:
                accessToken = oAuth2GrantService
                        .grant(GrantType.REFRESH_TOKEN, new HttpRefreshTokenRequest(request));
                break;
            default:
                ErrorType.UNSUPPORTED_GRANT_TYPE.throwThis(OAuth2Exception::new);
        }
        log.info(String.format("========步骤是:%d_方法是:%s_功能是:%s,参数是:%s", 6, "OAuth2AccessTokenController.requestToken", "根据code获取accessToken", JSON.toJSONString(accessToken)));
        return ResponseMessage.ok(entityToModel(accessToken));
    }


    protected AccessToken entityToModel(com.kedacom.ctsp.authz.oauth2.entity.AccessToken token) {
        AccessToken model = new AccessToken();
        model.setAccessToken(token.getAccessToken());
        model.setRefreshToken(token.getRefreshToken());
        model.setExpiresIn(token.getExpiresIn());
        model.setJwtToken(token.getJwtToken());
        if (token.getScope() != null) {
            model.setScope(token.getScope().stream().reduce((t1, t2) -> t1.concat(",").concat(t2)).orElse(""));
        } else {
            model.setScope(ScopeType.SCOPE_PULLIC);
        }
        model.setTokenType(TokenType.TOKEN_BEARER);
        return model;
    }

    @GetMapping("logout")
    public ResponseMessage<Object> logout(@RequestParam("client_id") String clientId, @RequestParam("access_token") String accessToken, HttpServletRequest request, HttpServletResponse response) {
        Authentication authentication = Authentication.current().orElseThrow(UnauthorizedException::new);
        ClientQueryParam param = new ClientQueryParam();
        param.setClientId(clientId);
        Client client = clientService.getCheckedClient(clientId);
        com.kedacom.ctsp.authz.oauth2.entity.AccessToken token = new SimpleAccessToken();
        token.setAccessToken(accessToken);
        token.setOwnerId(client.getOwnerId());
        token.setGrantType(GrantType.AUTHORIZATION_CODE);
        token.setClientId(param.getClientId());
        accessTokenService.removeAccessToken(token);
        logoutHandler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
        return ResponseMessage.ok();
    }

}
